package engine

import (
	"goruntimeDistributionCrawler/fetcher"
	"log"
	"time"
)

type WorkerManger func(r Request) (ParseResult,error)

type ConcurrentEngine struct {
	Scheduler Scheduler
	WorkerCount int
	ItemChan chan  Item
	WorkerManger WorkerManger
}

type Scheduler interface {
	ReadyChan
	Submit(Request)
	GetRequstChan() chan Request
	Run()
}
type ReadyChan interface {
	WorkerReady(chan Request)
} 

func (e *ConcurrentEngine) Run(seeds ...Request)  {

	out:=make(chan ParseResult)
	e.Scheduler.Run()
	for i:=0;i<e.WorkerCount ;i++  {
		createWorke(e.Scheduler.GetRequstChan(),out,e.Scheduler,e)
	}

	for _,r:=range seeds{
		e.Scheduler.Submit(r)
	}

	for {
		result:=<-out
		for _,item:=range result.Items{
                go func(item Item) {
                	e.ItemChan<-item
				}(item)
		}
		for _,request:=range result.Requests{
			e.Scheduler.Submit(request)
		}
	}
}

func createWorke(in chan Request,out chan  ParseResult,scheduler Scheduler,e *ConcurrentEngine)  {
	go func() {
		for {
			scheduler.WorkerReady(in)
            request:=<-in

            result,err:=e.WorkerManger(request)
			if err!=nil {
				continue
			}
            out<-result
		}
	}()
}


func  Worker(r Request) (ParseResult,error) {
	time.Sleep(time.Nanosecond)
	body,err:=fetcher.Fetch(r.UrL)
	if err !=nil {
		log.Printf("Fetcher error url:%s, eror:%v",r.UrL,err)
		return ParseResult{},err
	}
	return r.Parser.Parse(body,r.UrL),nil
}